#include "cinputaudiostream.h"

namespace buola { namespace media { namespace ffmpeg {

CInputAudioStream::CInputAudioStream(AVStream* pAV)
{
    mAV=pAV;
            
    mAV->codec->request_channels=2;

    AVCodec *lCodec=avcodec_find_decoder(mAV->codec->codec_id);
    if(!lCodec)
        throw XNotFound("can't find a suitable codec");

    if(avcodec_open2(mAV->codec,lCodec,nullptr)<0)
        throw XInternal("can't open codec");
}

void CInputAudioStream::SetPorts(blackbox::CStreamOut<int16_t> *pOut)
{
    oAudio=pOut;
}

template<typename tType>
static void fill_buffer_from_frame(CBuffer<int16_t> &pBuffer,AVFrame *pFrame,tType pScale=1)
{
    tType *lData1=reinterpret_cast<tType*>(pFrame->data[0]);
    tType *lData2=reinterpret_cast<tType*>(pFrame->data[1]);
    
    for(int i=0;i<pFrame->nb_samples;i++)
    {
        pBuffer[i*2]=(int16_t)(lData1[i]*pScale);
        pBuffer[i*2+1]=(int16_t)(lData2[i]*pScale);
    }
}

static CBuffer<int16_t> buffer_from_frame(AVFrame *pFrame)
{
    CBuffer<int16_t> lBuffer(pFrame->nb_samples*2);
    
    switch(pFrame->format)
    {
    case AV_SAMPLE_FMT_S16P:
        fill_buffer_from_frame<int16_t>(lBuffer,pFrame);
        break;
    case AV_SAMPLE_FMT_FLTP:
        fill_buffer_from_frame<float>(lBuffer,pFrame,32767.0f);
        break;
    default:
        throw XInvalid("unsupported audio format "+to_string(pFrame->format)+" in buffer_from_frame");
    }
    
    return lBuffer;
}

void CInputAudioStream::ProcessPacket(AVPacket* pPacket)
{
    msg_info() << "audio buffer\n";

    AVFrame *lFrame=avcodec_alloc_frame();
    
    int lGotFrame=0;
    
    int lRet=avcodec_decode_audio4(mAV->codec,lFrame,&lGotFrame,pPacket);

    if(lRet<0)
    {
        msg_error() << "error decoding audio frame!!!!!!!!!!\n";
        return;
    }

    oAudio->PushBuffer(buffer_from_frame(lFrame));
    avcodec_free_frame(&lFrame);
}

/*namespace ffmpeg*/ } /*namespace media*/ } /*namespace buola*/ }
